﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DARE
{
    
    public class CModelEmitter: AEmitter
    {
        #region identifier

        public enum ESpawnType : uint
        {
            FACES,
            EDGES
        }

        #endregion

        #region fields

        private Vector3[] positionsList;
        private Vector3[] normalsList;

        #endregion

        #region properties

        public AModel Model { get; set; }
        public ESpawnType SpawnType { get; set; }

        #endregion

        #region ctor

        public CModelEmitter(string name)
            :base(name)
        {
            positionsList = new Vector3[20000];
            normalsList = new Vector3[20000];
        }

        #endregion

        #region methods

        public override AEmitter Clone()
        {
            CModelEmitter pe = new CModelEmitter(Name);
            pe.EmissionInterval = EmissionInterval;
            pe.EmitPerEmission = EmitPerEmission;
            pe.MaxParticlesSimultaneous = MaxParticlesSimultaneous;
            pe.ReferenceParticle = ReferenceParticle;
            pe.Model = Model;
            return pe;
        }

        private void EmitEdges(IParticle particle)
        {
           /* if (Model is DARE.CBasicModel)
            {

                VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                VertexPositionNormalTextureTangentBinormal vertex = vertices[DARE.CDare.Instance.Random.Next(vertices.Length)];

                m_transformNode.Translate(vertex.Position, CNode.ESpace.LOCAL);

                Vector3 vec = vertex.Normal;
                particle.Position = m_transformNode.Position;

                Vector3 dir = vec * Velocities;

                particle.Velocities = dir;
            }
            else
            {
                CMesh mesh = (Model as DARE.CModel).Meshes[DARE.CDare.Instance.Random.Next((Model as DARE.CModel).Meshes.Length)];
                CMeshPart part = mesh.Parts[DARE.CDare.Instance.Random.Next(mesh.Parts.Length)];

                VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[part.MeshPart.VertexBuffer.VertexCount];
                part.MeshPart.VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                VertexPositionNormalTextureTangentBinormal vertex = vertices[DARE.CDare.Instance.Random.Next(vertices.Length)];


                Matrix world = mesh.MeshWorld;

                Vector3 position = vertex.Position * Model.Scale;

                m_transformNode.Translate(position, CNode.ESpace.LOCAL);

                Vector3 vec = vertex.Normal;
                particle.Position = m_transformNode.Position;

                Vector3 dir = vec * Velocities;

                particle.Velocities = dir;
            }*/
            int id = DARE.CDare.Instance.Random.Next(20000);
            m_transformNode.Translate(positionsList[id], CNode.ESpace.LOCAL);
            particle.Position = m_transformNode.Position;
            particle.Velocities = normalsList[id] * Velocities;
        }

        public void PrecalculatePointsAndNormals()
        {
            for (int i = 0; i < 20000; ++i)
            {
                if (SpawnType == ESpawnType.FACES)
                {
                    if (Model is DARE.CBasicModel)
                    {
                        if ((Model as DARE.CBasicModel).IndexBuffer == null)
                        {
                            VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                            (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);
                            int id = DARE.CDare.Instance.Random.Next(vertices.Length);
                            id -= id % 3;
                            VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id];
                            VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id + 1];
                            VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id + 2];

                            float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                            float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                            float b2 = 1 - b0 - b1;

                            Vector3 pos = vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2;
                            Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                            positionsList[i] = pos;
                            normalsList[i] = vec;
                        }
                        else
                        {
                            short[] indices = new short[(Model as DARE.CBasicModel).IndexBuffer.IndexCount];
                            (Model as DARE.CBasicModel).IndexBuffer.GetData<short>(indices);
                            int id0 = DARE.CDare.Instance.Random.Next(indices.Length);
                            id0 -= id0 % 3;
                            id0 = indices[id0];
                            int id1 = indices[id0 + 1];
                            int id2 = indices[id0 + 2];
                            VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                            (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);
                            VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id0];
                            VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id1];
                            VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id2];

                            float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                            float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                            float b2 = 1 - b0 - b1;

                            Vector3 pos = vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2;
                            Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                            positionsList[i] = pos;
                            normalsList[i] = vec;

                        }
                    }
                    else
                    {
                        CMesh mesh = (Model as DARE.CModel).Meshes[DARE.CDare.Instance.Random.Next((Model as DARE.CModel).Meshes.Length)];
                        CMeshPart part = mesh.Parts[DARE.CDare.Instance.Random.Next(mesh.Parts.Length)];

                        short[] indices = new short[part.MeshPart.IndexBuffer.IndexCount];
                        part.MeshPart.IndexBuffer.GetData<short>(indices);
                        int id0 = DARE.CDare.Instance.Random.Next(indices.Length);
                        id0 -= id0 % 2;
                        id0 = indices[id0];
                        int id1 = indices[id0 + 1];
                        int id2 = indices[id0 + 2];


                        VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[part.MeshPart.VertexBuffer.VertexCount];
                        part.MeshPart.VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                        VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id0];
                        VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id1];
                        VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id2];

                        float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                        float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                        float b2 = 1 - b0 - b1;

                        Vector3 pos = (vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2) * Model.Scale;
                        Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                        positionsList[i] = pos;
                        normalsList[i] = vec;
                    }
                }
                else if (SpawnType == ESpawnType.EDGES)
                {
                    if (Model is DARE.CBasicModel)
                    {

                        VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                        (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                        VertexPositionNormalTextureTangentBinormal vertex = vertices[DARE.CDare.Instance.Random.Next(vertices.Length)];

                        m_transformNode.Translate(vertex.Position, CNode.ESpace.LOCAL);

                        Vector3 pos = vertex.Position;
                        Vector3 vec = vertex.Normal;
                        positionsList[i] = pos;
                        normalsList[i] = vec;
                    }
                    else
                    {
                        CMesh mesh = (Model as DARE.CModel).Meshes[DARE.CDare.Instance.Random.Next((Model as DARE.CModel).Meshes.Length)];
                        CMeshPart part = mesh.Parts[DARE.CDare.Instance.Random.Next(mesh.Parts.Length)];

                        VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[part.MeshPart.VertexBuffer.VertexCount];
                        part.MeshPart.VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                        VertexPositionNormalTextureTangentBinormal vertex = vertices[DARE.CDare.Instance.Random.Next(vertices.Length)];


                        Matrix world = mesh.MeshWorld;

                        Vector3 position = vertex.Position * Model.Scale;
                        positionsList[i] = position;
                        normalsList[i] = vertex.Normal;
                    }
                }
            }
        }

        private void EmitFaces(IParticle particle)
        {
            /*if (Model is DARE.CBasicModel)
            {
                if ((Model as DARE.CBasicModel).IndexBuffer == null)
                {
                    VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                    (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);
                    int id = DARE.CDare.Instance.Random.Next(vertices.Length);
                    id -= id % 3;
                    VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id];
                    VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id + 1];
                    VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id + 2];

                    float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                    float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                    float b2 = 1 - b0 - b1;

                    Vector3 pos = vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2;

                    m_transformNode.Translate(pos, CNode.ESpace.LOCAL);

                    Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                    particle.Position = m_transformNode.Position;

                    Vector3 dir = vec * Velocities;

                    particle.Velocities = dir;
                }
                else
                {
                    short[] indices = new short[(Model as DARE.CBasicModel).IndexBuffer.IndexCount];
                    (Model as DARE.CBasicModel).IndexBuffer.GetData<short>(indices);
                    int id0 = DARE.CDare.Instance.Random.Next(indices.Length);
                    id0 -= id0 % 3;
                    id0 = indices[id0];
                    int id1 = indices[id0 + 1];
                    int id2 = indices[id0 + 2];
                    VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[(Model as DARE.CBasicModel).VertexBuffer.VertexCount];
                    (Model as DARE.CBasicModel).VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);
                    VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id0];
                    VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id1];
                    VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id2];

                    float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                    float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                    float b2 = 1 - b0 - b1;

                    Vector3 pos = vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2;

                    m_transformNode.Translate(pos, CNode.ESpace.LOCAL);

                    Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                    particle.Position = m_transformNode.Position;

                    Vector3 dir = vec * Velocities;

                    particle.Velocities = dir;
                }
            }
            else
            {
                CMesh mesh = (Model as DARE.CModel).Meshes[DARE.CDare.Instance.Random.Next((Model as DARE.CModel).Meshes.Length)];
                CMeshPart part = mesh.Parts[DARE.CDare.Instance.Random.Next(mesh.Parts.Length)];

                short[] indices = new short[part.MeshPart.IndexBuffer.IndexCount];
                part.MeshPart.IndexBuffer.GetData<short>(indices);
                int id0 = DARE.CDare.Instance.Random.Next(indices.Length);
                id0 -= id0 % 3;
                id0 = indices[id0];
                int id1 = indices[id0 + 1];
                int id2 = indices[id0 + 2];


                VertexPositionNormalTextureTangentBinormal[] vertices = new VertexPositionNormalTextureTangentBinormal[part.MeshPart.VertexBuffer.VertexCount];
                part.MeshPart.VertexBuffer.GetData<VertexPositionNormalTextureTangentBinormal>(vertices);

                VertexPositionNormalTextureTangentBinormal vertex0 = vertices[id0];
                VertexPositionNormalTextureTangentBinormal vertex1 = vertices[id1];
                VertexPositionNormalTextureTangentBinormal vertex2 = vertices[id2];

                float b0 = (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                float b1 = (1.0f - b0) * (DARE.CDare.Instance.Random.Next(100) / 100.0f);
                float b2 = 1 - b0 - b1;

                Vector3 pos = vertex0.Position * b0 + vertex1.Position * b1 + vertex2.Position * b2;

                Matrix world = mesh.MeshWorld;

                pos *= Model.Scale;

                m_transformNode.Translate(pos, CNode.ESpace.LOCAL);

                Vector3 vec = vertex0.Normal * b0 + vertex1.Normal * b1 + vertex2.Normal * b2;
                particle.Position = m_transformNode.Position;

                Vector3 dir = vec * Velocities;

                particle.Velocities = dir;
            }*/
            int id = DARE.CDare.Instance.Random.Next(20000);
            m_transformNode.Translate(positionsList[id], CNode.ESpace.LOCAL);
            particle.Position = m_transformNode.Position;
            particle.Velocities = normalsList[id] * Velocities;

        }

        public override void GetParametersFromEmitter(IParticle particle)
        {
            m_transformNode.Position = m_node.Position;
            m_transformNode.Orientation = m_node.Orientation;
            m_transformNode.NScale = m_node.NScale;

            if (Model == null)
                return;
            if (SpawnType == ESpawnType.EDGES)
            {
                EmitEdges(particle);
            }
            else if (SpawnType == ESpawnType.FACES)
            {
                EmitFaces(particle);
            }
        }
        #endregion
    }
}
